package org.fuys.coder.domain.signup.service.impl;

import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.common.constants.RedisConstants;
import org.fuys.coder.common.util.BitOperationUtil;
import org.fuys.coder.domain.signup.repository.IUserSignUpRepository;
import org.fuys.coder.domain.signup.service.ISignUpService;
import org.fuys.coder.domain.user.service.repo.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.LocalDate;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.signup.service.impl
 * @className: SignUpService
 * @author: WangJing
 * @description: 签到服务实现类
 * @date: 2024/6/29 21:39
 * @version: 1.0
 */
@Service
public class SignUpService implements ISignUpService {

    //具体思路 分两种情况
    //1.在月内的签到
    //这个很简单 依照Redis的hash结构对应的用户key 修改 key对应的bitmap即可 如下
    //hash----------> key1 -------> bitmap1(31位)
    //  |-----------> key2 -------> bitmap2(31位)
    //user:sign:11--> user:id1 ---> 0000000000000000000000000000001
    //  |-----------> user:id2 ---> 0000000000000000000000000000001
    //这样修改和设置很简单
    //2.在月份更替时的签到
    //这个就不是那么简单了 因为我们要清理掉之前的签到记录 我现在想到的思路是 提前创建出下个月份的redis Key 防止大量并发
    //如 在四月更替的时候 创建出6月的key 同样的 在5月的时候 创建出7月的key 在应用初次上线的时候 是直接创建出两个key即可
    //采用hash结构 可以轻松的获取用户对应的bitmap 在清除的时候也非常容易清除 直接删除全部的redisKey即可
    //至于持久化策略 在什么时候持久化到数据库呢？ 不是很确定 先放一下把

    @Resource
    private IUserSignUpRepository userSignUpRepository;

    @Resource
    private IUserService userService;

    @Override
    public boolean userSignUp(Integer userId,Integer point) {
        //todo 或许这里可以优化 让获取时间这个步骤简单一些？
        String redisKey= RedisConstants.REDIS_USE_SIGN_UP+RedisConstants.REDIS_SPLIT
                + LocalDate.now().getMonthValue();
        String fieldKey= RedisConstants.REDIS_FIELD_USER+userId;
        final Object o = userSignUpRepository.getUserSignupInfo(redisKey,fieldKey);
        long value=0L;
        //这里的减去一位并不是因为它返回的不对啊 是因为31位需要是0~30
        final int day = LocalDate.now().getDayOfMonth() - 1;
        if(!ObjectUtils.isEmpty(o)){
            //如果不为空 就需要进行检查了
            value= Long.parseLong(o.toString());
            if(BitOperationUtil.getLongBit(value,day)){
                return false;
            }
        }
        final long bitValue = BitOperationUtil.setLongBit(value, day, true);
        userSignUpRepository.doUserSignup(redisKey,fieldKey,bitValue);
        userService.updateUserPoint(userId,point);
        return true;
    }

    @Override
    public Pair<Integer,byte[]> userSignInfo(Integer userId) {
        String redisKey= RedisConstants.REDIS_USE_SIGN_UP+RedisConstants.REDIS_SPLIT
                +LocalDate.now().getMonthValue();
        final Object o = userSignUpRepository.getUserSignupInfo(redisKey, RedisConstants.REDIS_FIELD_USER + userId);
        if(ObjectUtils.isEmpty(o)){
            //如果是空 说明还没有进行签到操作
            return null;
        }
        return BitOperationUtil.getLongBitInfo(Long.parseLong(o.toString()));
    }
}
